/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - initial API and implementation
 */
package de.ipk_gatersleben.bit.bi.edal.primary_data.reference;

import java.util.Arrays;
import java.util.Calendar;
import java.util.List;

import de.ipk_gatersleben.bit.bi.edal.primary_data.DataManager;
import de.ipk_gatersleben.bit.bi.edal.primary_data.EdalConfigurationException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.reference.ReviewStatus.ReviewStatusType;
import de.ipk_gatersleben.bit.bi.edal.primary_data.reference.ReviewStatus.ReviewerType;

/**
 * Class to handle interaction between eDAL and the ReviewProcess.
 * 
 * @author arendd
 * 
 */
public class ReviewProcess {

	/**
	 * the default timeout for the review process 5 days in milliseconds
	 */
	private static final int DEFAULT_TIMEOUT = 432000000;

	/**
	 * Checks with specific rules the review status of a publication.
	 * 
	 * @param reviewStatusList
	 *            list with all reviewer they have responded
	 * @return list with all reviewers
	 * @throws EdalApprovalException
	 *             if wrong email address
	 */
	public static ReviewResult review(List<ReviewStatus> reviewStatusList)
			throws EdalApprovalException {

		// Result of the review process
		ReviewResult reviewResult = new ReviewResult();

		// initial step, no reviewers was notified
		if (reviewStatusList.size() == 0) {
			try {
				// create the scientific reviewer
				ReviewStatus scientificReviewStatus = new ReviewStatus();
				scientificReviewStatus.setEmailAddress(DataManager
						.getConfiguration().getReviewerScientific());
				scientificReviewStatus
						.setStatusType(ReviewStatusType.UNDECIDED);
				scientificReviewStatus.setRequestedDate(Calendar.getInstance());
				scientificReviewStatus.setReviewerType(ReviewerType.SCIENTIFIC);

				// create the substitute reviewer
				ReviewStatus substituteReviewStatus = new ReviewStatus();
				substituteReviewStatus.setEmailAddress(DataManager
						.getConfiguration().getReviewerSubstitute());
				substituteReviewStatus
						.setStatusType(ReviewStatusType.UNDECIDED);
				substituteReviewStatus.setRequestedDate(Calendar.getInstance());
				substituteReviewStatus.setReviewerType(ReviewerType.SUBSTITUTE);

				// create the managing reviewer
				ReviewStatus managingReviewStatus = new ReviewStatus();
				managingReviewStatus.setEmailAddress(DataManager
						.getConfiguration().getReviewerManaging());
				managingReviewStatus.setStatusType(ReviewStatusType.UNDECIDED);
				managingReviewStatus.setRequestedDate(Calendar.getInstance());
				managingReviewStatus.setReviewerType(ReviewerType.MANAGING);

				// list with all reviewers there get an email notification
				reviewResult.setReviewerStatusList(Arrays.asList(
						scientificReviewStatus, substituteReviewStatus,
						managingReviewStatus));

				// in this case the result is always undecided
				reviewResult.setReviewStatusType(ReviewStatusType.UNDECIDED);

				return reviewResult;

			} catch (EdalConfigurationException e) {
				throw new EdalApprovalException(e);
			}

		} else {
			// check if the parameter size is correct
			if (reviewStatusList.size() != 3) {
				throw new EdalApprovalException(
						"Unexpected reviewStatusList size. Expected was 3 but list size was "
								+ reviewStatusList.size() + ".");
			}

			// get the 3 reviewStatus
			ReviewStatus scientificReviewStatus = null;
			ReviewStatus substituteReviewStatus = null;
			ReviewStatus managingReviewStatus = null;

			for (ReviewStatus reviewStatus : reviewStatusList) {
				switch (reviewStatus.getReviewerType()) {
				case SCIENTIFIC:
					scientificReviewStatus = reviewStatus;
					break;

				case SUBSTITUTE:
					substituteReviewStatus = reviewStatus;
					break;

				case MANAGING:
					managingReviewStatus = reviewStatus;
					break;
				}
			}

			// Review Rules
			// is the timeout not exceeded
			if (!isTimeoutExceeded(managingReviewStatus.getRequestedDate())) {
				// is the managing reviewer undecided, then return undecided.
				if (managingReviewStatus.getStatusType().equals(
						ReviewStatusType.UNDECIDED)) {

					reviewResult
							.setReviewStatusType(ReviewStatusType.UNDECIDED);
					return reviewResult;
				}
				// Is the managing reviewer not undecided, then return his
				// answer.
				else {
					reviewResult.setReviewStatusType(managingReviewStatus
							.getStatusType());
					return reviewResult;
				}
			}
			// the timeout is exceeded
			else {
				// is the managing reviewer not undecided then return his
				// answer.
				if (!managingReviewStatus.getStatusType().equals(
						ReviewStatusType.UNDECIDED)) {

					reviewResult.setReviewStatusType(managingReviewStatus
							.getStatusType());
					return reviewResult;
				}
				// is the scientific reviewer not undecided then return his
				// answer.
				else if (!scientificReviewStatus.getStatusType().equals(
						ReviewStatusType.UNDECIDED)) {

					reviewResult.setReviewStatusType(scientificReviewStatus
							.getStatusType());
					return reviewResult;
				}
				// is the substitute reviewer not undecided then return his
				// answer.
				else if (!substituteReviewStatus.getStatusType().equals(
						ReviewStatusType.UNDECIDED)) {

					reviewResult.setReviewStatusType(substituteReviewStatus
							.getStatusType());
					return reviewResult;
				}
				// has nobody an answer then return rejected
				else {
					reviewResult.setReviewStatusType(ReviewStatusType.REJECTED);
					return reviewResult;
				}
			}

		}
	}

	/**
	 * Checks if the timeout of the review process is exceeded with a specific
	 * requested date.
	 * 
	 * @param requestedDate
	 *            the date when the Reviewer was notified with an email
	 * @return <code>true</code> if the timeout is exceeded <code>false</code>
	 *         otherwise
	 */
	private static boolean isTimeoutExceeded(Calendar requestedDate) {
		Calendar now = Calendar.getInstance();
		long difference = now.getTimeInMillis()
				- requestedDate.getTimeInMillis();

		return difference > ReviewProcess.DEFAULT_TIMEOUT ? true : false;
	}
}
